package de.windeln.google.service;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import com.google.api.services.analytics.Analytics;
import com.google.api.services.analytics.model.McfData;
import com.google.api.services.analytics.model.McfData.ColumnHeaders;

public class ReportAccess {

	/** current date. */
	private static String date;

	/**
	 * Returns the required dimensions and metrics of a given date. The MCF
	 * Reporting API is used to retrieve this data.
	 * 
	 * @param analytics
	 *            the analytics service object used to access the API.
	 * @param profileId
	 *            the profile ID from which to retrieve data.
	 * @return the response from the API.
	 * @throws IOException
	 *             if an API error occurred.
	 */
	public McfData executeDataQuery(Analytics analytics, String profileId)
			throws IOException {

		return analytics
				.data()
				.mcf()
				.get("ga:" + profileId,
						createStartDate(),
						createEndDate(),
						"mcf:totalConversions, mcf:totalConversionValue, mcf:assistedConversions, mcf:assistedValue, mcf:firstInteractionConversions, mcf:firstInteractionValue, mcf:lastInteractionConversions, mcf:lastInteractionValue")
				.setDimensions(
						"mcf:keyword, mcf:basicChannelGrouping, mcf:sourceMedium, mcf:sourceMediumPath, mcf:campaignName, mcf:adwordsMatchType, mcf:adwordsCampaignPath")
				.setMaxResults(10).execute();
	}

	/**
	 * Prints the output from the MCF Reporting API. The profile name is printed
	 * along with each column name and all the data in the rows.
	 * 
	 * @param results
	 *            data returned from the MCF Reporting API.
	 */
	public void printDataTable(McfData mcfData) throws IOException {
		FileOutputStream fos = new FileOutputStream("MCF_Report_" + date
				+ ".csv");
		OutputStreamWriter osw = new OutputStreamWriter(fos);
		BufferedWriter bw = new BufferedWriter(osw);
		System.out.println("Data Table:");
		if (mcfData.getTotalResults() > 0) {
			// Print the column names.
			List<ColumnHeaders> headers = mcfData.getColumnHeaders();
			for (ColumnHeaders header : headers) {
				System.out.printf("%30s", header.getName());
				String h = new String();
				h = header.getName().split(":")[1];
				bw.write(h);
				bw.write(",");
				bw.flush();
			}
			System.out.println();
			bw.newLine();

			// Print the rows of data.
			for (List<McfData.Rows> row : mcfData.getRows()) {
				for (int columnIndex = 0; columnIndex < row.size(); ++columnIndex) {
					ColumnHeaders header = headers.get(columnIndex);
					McfData.Rows cell = row.get(columnIndex);
					if (header.getDataType().equals("MCF_SEQUENCE")) {
						System.out.printf("%30s", getStringFromMcfSequence(cell
								.getConversionPathValue()));
						bw.write(getStringFromMcfSequence(cell
								.getConversionPathValue()));
						bw.write(",");
						bw.flush();
					} else {
						System.out.printf("%30s", cell.getPrimitiveValue());
						bw.write(cell.getPrimitiveValue());
						bw.write(",");
						bw.flush();
					}
				}
				System.out.println();
				bw.newLine();
			}
		} else {
			System.out.println("No rows found");
		}

		bw.close();
	}

	private static String getStringFromMcfSequence(
			List<McfData.Rows.ConversionPathValue> path) {
		StringBuilder stringBuilder = new StringBuilder();
		for (McfData.Rows.ConversionPathValue pathElement : path) {
			if (stringBuilder.length() > 0)
				stringBuilder.append(" > ");
			stringBuilder.append(pathElement.getNodeValue());
		}
		return stringBuilder.toString();
	}

	/**
	 * Substracts 2 days from the current date.
	 * 
	 * @return date two days before today
	 */
	private static String createDate() {

		GregorianCalendar calendar = new GregorianCalendar();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		calendar.add(Calendar.DATE, -2);
		date = sdf.format(calendar.getTime());
		return date;
	}

	/**
	 * Substracts 2 days from the current date.
	 * 
	 * @return date two days before today
	 */
	private static String createStartDate() {

		return createDate();
	}

	/**
	 * Substracts 2 days from the current date.
	 * 
	 * @return date two days before today
	 */
	private static String createEndDate() {

		return createDate();
	}

}
